package com.rt.easyjava.common.aop;

import com.rt.easyjava.common.base.Result;
import com.rt.easyjava.common.base.UserDetailsDto;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.ContentCachingRequestWrapper;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Enumeration;

@Component
@Aspect
@Slf4j
public class MethodCostAspect {


/*    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        ContentCachingRequestWrapper wrappedRequest = new ContentCachingRequestWrapper(request);

        filterChain.doFilter(wrappedRequest, response);

    }*/

    @Pointcut("execution(public * com.rt.*..*.controller..*.*(..)) || " +
            "execution(public * com.rt.*.*..*.controller..*.*(..))")
    public void managerMethods() {
    }

    @Around("managerMethods()")
    public Object printMethodCost(ProceedingJoinPoint joinPoint) {
        String traceLogId = getTraceLogId();
        Long beginTime = System.currentTimeMillis();
        Long endTime;
        String methodCnName = "";
        String requestUrl = "";
        try {
            RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
            requestUrl = getRequestUri(joinPoint, traceLogId, request);
            try {
                methodCnName = ((MethodSignature) joinPoint.getSignature()).getMethod().getAnnotation(ApiOperation.class).value();
            }catch (Exception e){}
            String userDetailsJson = request.getParameter("userDetailsJson");
            UserDetailsDto user = UserDetailsDto.getUserDetailsDto(userDetailsJson);
            if (null != user) {
                //log.info("【{}】- methodName:{}, userName:{},deptName：{},params:{}", traceLogId, methodCnName, user.getUserName(), user.getDeptName());
            }
        } catch (Exception e) {
            //log.warn("【{}】- 尝试打印请求参数发生错误，无法获取获取用户信息及方法名称。", traceLogId);
        }

        try {
            Object result = joinPoint.proceed();
            endTime = System.currentTimeMillis();
            if (result instanceof Result) {
                Result res = (Result) result;
                String resStr = res.toString();
                if (null != resStr && resStr.length() > 400) {
                    resStr = resStr.substring(0, 400).concat("...");
                }
                log.info("===>AOP:{} 请求处理结束，本次处理耗时(ms):{},处理结果：{}", traceLogId, endTime - beginTime, resStr);
            } else {
                log.warn("===>AOP:{} 请求处理结束- 本次请求返回非标准结果（返回类型:{})。本次处理耗时(ms):{},处理结果：{}", traceLogId, null == result ? "" : result.getClass().getName(), endTime - beginTime, result);
            }
            return result;
        } catch (Exception e) {
            log.error("===>AOP:{} 当前请求发生错误错误，异常信息:{}", traceLogId, e);
            return Result.builder().fault("本次请求发生错误，请稍后再试！");
        } catch (Throwable throwable) {
            log.error("===>AOP:{} 当前请求发生错误错误，异常信息:{}", traceLogId, throwable);
            return Result.builder().fault("本次请求发生错误，请稍后再试！");
        }
    }


    private String getRequestUri(ProceedingJoinPoint joinPoint, String traceLogId, HttpServletRequest request) {
        String className = joinPoint.getTarget().getClass().getName();
        className = className.substring(className.lastIndexOf(".") + 1);
        String methodName = joinPoint.getSignature().getName();
        String requestUrl = className + "." + methodName;
        String param = getDataFromRequest(request, traceLogId);
        log.info("===>AOP:{}- 请求开始! requestUri:{},请求参数:{}", traceLogId, requestUrl, param);
        return requestUrl;
    }


    private String getTraceLogId() {
        String mills = String.valueOf(System.currentTimeMillis());
        String tail = String.valueOf((int) Math.round(Math.random() * (9999 - 1000) + 1000));
        return mills + tail;
    }


    private String getDataFromRequest(HttpServletRequest request, String traceLogId) {
        String type = request.getContentType();
        if (type == null) type = "application/x-www-form-urlencoded";
        // Map<String,Object> receiveMap = new HashMap<String,Object>();
        StringBuilder sb = new StringBuilder();
        sb.append("params:");
        if ("application/x-www-form-urlencoded".equals(type)) {
            Enumeration<String> enu = request.getParameterNames();
            while (enu.hasMoreElements()) {
                String key = String.valueOf(enu.nextElement());
                String value = request.getParameter(key);
                // receiveMap.put(key, value);
                sb.append(key).append(":").append(value).append(",");
            }
        } else {    //else是text/plain、application/json这两种情况
            /*BufferedReader reader = null;
            try {
                reader = new BufferedReader(new InputStreamReader(request.getInputStream(), "utf-8"));
                String line = null;
                while ((line = reader.readLine()) != null) {
                    sb.append(line);
                }
            } catch (IOException e) {
                // e.printStackTrace();
            } finally {
                try {
                    if (null != reader) {
                        reader.close();
                    }
                } catch (IOException e) {
                    log.error("【{}】获取请求参数发生异常，错误信息:{}", traceLogId, e);
                }
            }*/
        }
        String params = sb.toString();
        if (null != params && params.length() > 500) {
            params = params.substring(0, 500).concat("...");
        }
        return params;
    }

}



